
package com.starshineworks.util;

import com.starshineworks.entities.*;
import com.starshineworks.util.actions.Action;

import java.util.*;
import java.io.*;
//import java.security.MessageDigest;
//import java.io.UnsupportedEncodingException;
//import java.security.MessageDigest;
//import java.security.NoSuchAlgorithmException;
//import org.myorg.SystemUnavailableException;
//import sun.misc.BASE64Encoder;
//import sun.misc.CharacterEncoder;
 

import javax.servlet.*;
import javax.servlet.http.*;

public class Util {

    public static final int HTMLViewNone  = 0; 
    public static final int HTMLViewTable = 1; 
    public static final int HTMLViewForm  = 2; 

    public static String generateMagic() 
    { 
        Random rand = new Random();
        Integer r = rand.nextInt(20) + 100;
        String hex = "";
        Long x = -1L;
        x = x - Long.MAX_VALUE;
        hex = Long.toHexString(x);
        long n = (new Date()).getTime();
        x = x + n;
        hex = Long.toHexString(x);
        String magic = "m" + hex + "x" + r + "e";
        return magic;
    }
       
    public static String MD5(String md5) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(md5.getBytes());
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < array.length; ++i) {
                sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            Util.handleException(e);
        }
        return null;
    }
    
    public static String hide(String s) 
    {
        String z = MD5(s);
        if (z != null) {
            return z;
        }
        z = "";
        Integer len = s.length();
        while (len > 0) {
            --len;
            z += ("X" + s.charAt(len) + len.toString());
        }
        return z;
    }

    public static void serveForm(HttpServletRequest  request, 
                                 HttpServletResponse response, 
                                 HttpServlet         servlet,
                                 String              actVal)
            throws ServletException, IOException 
    {
        Action action;
        String actionValue = actVal;
        boolean isMultiPart = true;
        if (!Util.isMultiPart(request)) {
            actionValue = request.getParameter("action");
            isMultiPart = false;
        }
        if (actionValue != null) {
            action = Action.createAction(actionValue);
            if (action != null) {
                if (action.perform(request, response, servlet, isMultiPart)) {
                    response.sendRedirect(action.getNextPage());
                    return;
                }
                showError(request, response, action.getError());
                return;
            }
        }
        showError(request, response, "(Unknown error)");
    }

    public static void showError(HttpServletRequest  request, 
                                 HttpServletResponse response,
                                 String              error)
            throws ServletException, IOException 
    {      
        String      close = "Start";
        HttpSession sess  = request.getSession(false);
        if (sess != null) {
            if (!sess.isNew()) {
                Integer uId = (Integer)sess.getAttribute("uId");
                if (uId != null) {
                    close = "User";
                }
            }
        }
        request.setAttribute("page", "Error.get");
        request.setAttribute("close", close);
        request.setAttribute("error", error);
        RequestDispatcher view = request.getRequestDispatcher("/WEB-INF/pages/Layout.jsp");
        view.forward(request, response);
    }

    public static void showForm(HttpServletRequest  request, 
                                HttpServletResponse response, 
                                String              page,
                                boolean             needSession,
                                boolean             needAdmin,
                                boolean             needComplete) 
            throws ServletException, IOException 
    {
        String      error   = null;
        boolean     ok      = true;
        HttpSession sess    = null;
        Integer     uId     = null;
        
        // The session and user check is a bit asymmetric.
        if (ok && needSession) {
            ok = false;
            sess = request.getSession(false);
            if (sess != null) {
                if (!sess.isNew()) {
                    uId = (Integer)sess.getAttribute("uId");
                    if (uId != null) {
                        ok = true;
                    }
                }
            }
            if (!ok) {
                error = "Invalid session. Please logout and try again.";
            }
        }
        
        // The remaining checks are simpler.
        if (ok && needAdmin) {
            if (!UserE.isAdmin(uId)) {
                ok = false;
                error = "Only administrators can access this page.";
            }
        }
        if (ok && needComplete) {
            if (!UserE.isComplete(uId)) {
                ok = false;
                error = "You must complete your user information before accessing this page.";
            }
        }

        // Done with checks.
        if (!ok) {
            if (error == null) {
                error = "(Unknown error)";
            } 
            showError(request, response, error);
            return;
        }
        
        // Go to requested page.
        request.setAttribute("page", page + ".get");
        RequestDispatcher view = request.getRequestDispatcher("/WEB-INF/pages/Layout.jsp");
        view.forward(request, response);
    }

    public static String getPageOfEntity(Object obj) {
        String cl = obj.getClass().getSimpleName();
        // Remove the final 'E' from the class name.
        cl = cl.substring(0, cl.length() - 1);
        return cl + "Page";
    }

    public static boolean isMultiPart(HttpServletRequest request) {
        boolean m = request.getContentType() != null && 
                    request.getContentType().toLowerCase().indexOf("multipart/form-data") > -1;
        return m;
    }
    
    public static final String os         = System.getProperty("os.name");
    public static final String userHome   = System.getProperty("user.home");
    public static final boolean isWindows = os.startsWith("Win");

    private static int baseId = 0;
    private static int nextId = 0;
    private static final int maskId = 100000;
    private static int m_objectId = 7000;

    private static synchronized int getNextId() {
        m_objectId++;
        return m_objectId;
    }
    /* XXXXX
        int b = 0;
        try {
            
            if (true) {
                while (locked && count > 0) {
                    Thread.sleep(500);
                }
                if (count == 0) {
                    throw new Exception("Unable to get ID lock.");
                }
                locked = true;
                b = fallbackId;
                fallbackId++;
                locked = false;
                return b;
            }
            /* Obsolete?
            grabLock();
            Scanner in1 = new Scanner(idlock);
            b = in1.nextInt();
            Integer nxt = b + 1;
            FileWriter fw = new FileWriter(idlock);
            fw.write(nxt.toString());
            fw.flush();
            releaseLock();
            * */
    /*
        } catch (Exception e) {
            Util.handleException(e);
            Date d = new Date();
            Long n = 0x0ffffffff & (d.getTime() / (1024 * 62));
            b = n.intValue();
        }
        return b;
    }*/

    /* XXX
    static boolean grabLock() {
        return updateLock(true);
    }

    static boolean updateLock(boolean phase) {
        File fromfile = idfile;
        File tofile = idlock;
        if (!phase) {
            fromfile = idlock;
            tofile = idfile;
        }
        boolean changed = false;
        while (!changed) {
            try {
                changed = fromfile.renameTo(tofile);
            } catch (Exception e) {
            Util.handleException(e);
            }
        }
        return changed;
    }

    static boolean releaseLock() {
        return updateLock(false);
    }*/
    
    @SuppressWarnings("CallToThreadDumpStack")
    public static Integer nextId() {
        baseId = getNextId();         
        nextId = baseId + maskId;
        return nextId;
    }
    
    public static <T> T[] concatArrays(T[] first, T[] second) {
        T[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    public static Map<String,String[]> adjustMapNames(Map<String,String[]> a) {
       Map<String,String[]> b = new HashMap<String,String[]>();
       for (Map.Entry<String, String[]> entry : a.entrySet()) {
           String key = entry.getKey();
           String[] value = entry.getValue();
           String kk = key.replace("[]", "");
           b.put(kk, value);
       }
       return b;
    }
        
    public static String asHTMLTable(List<String> k, List<List<String>> t)
    {
        if (k != null) {
            t.add(0, k);
        }
        int clen = t.size();
        // XXX int bg = 0x0eee;
        String[] csty = new String[clen];
        int len = 0;
        int n = clen;
        for (List<String> row : t) {
            int l = row.size();
            if (l > len) {
                len = l;
            }
            n--;
            //int bg = 0x0eef;
            /* if (k != null && n == 0) {
                bg = 0x0ddd;
            }*/
            //sty[n] = " ";//border:solid 1px ; ";//background-color:"+Integer.toHexString(bg)+";";
            //bg -= 0x0111;
        }
        String y = "<div style='border:solid 1px #ffe682;'><table>";
        y += "<tr><td><div style='width:180px'></div></td>";
        y += "<td colspan="+(clen-1)+" ><div style='width:240px'></div></tr>";
        for (int r = 0; r < len; r++) {
            y += "<tr>";
            for (int c = 0; c < clen; c++) {
                String stl = (c == 0 ? " style='color:#3059d6' " : "");
                y += "<td style='border-bottom:solid 1px #ffe682;padding:6px;"+csty[c]+"'><p "+stl+">";
                String rc;
                try {
                    rc = t.get(c).get(r);
                }
                catch (Exception e) {
                    rc = "<b>**?**</b>";
                }
                y += rc;
                y += "</p></td>";
            }
            y += "</tr>";
        }
        y += "</table></div>";
        return y;
    }
    
    public static boolean sendEmail(String to, String from, 
                                    String subject, String text,
                                    String attachment)
    {
        return (new Emailer()).send(to, from, subject, text, attachment);
    }
    
    public static String addPlainText(String name, String val, String[] opts)
    {
        String y = "<p>"+val+"</p>";
        return y;
    }
    
    public static String addButton(String script, String val, String[] opts)
    {
        String y = "<input type=button value=\""+val+"\" onclick='"+script+";return false;' />";
        return y;
    }
    
    public static String addSubmitInput(String name, String val, String[] opts) 
    {
        String y = // m m m mXXXX "<input name="+name+" type=submit value=\""+val+"\" />";
                "<div id=ssw_submit><button onclick=\"return validateForm(this)\" type=button id=ssw_submit >Submit</button></div>";
        // XXXXX
        //"<script>\n    document.write(submitButtonDiv('Submit'));\n</script>";
        return y;
    }

    public static String addHiddenInput(String name, String val, String[] opts) 
    {
        String y = "<input type=hidden value="+val+" name="+name+" />";
        return y;
    }
    
    public static String addTextInput(String name, String value, boolean enabled) //String[] opts) 
    {
        String dis = enabled ? "" : " disabled ";        
        String y = "<input "+dis+"name="+name+" value=\""+value+"\" />";
        return y;
    }
    
    public static String addSelectInput(String name, String val, String[] opts) 
    {
        int len = opts.length;
        String y = "<select name="+name+">";
        for (int j = 0; j < len; j++) {
            String sel = "";
            if (opts[j].equalsIgnoreCase(val)) {
                sel = " selected=selected ";
            }
            y += "<option "+sel+" value="+opts[j]+">"+opts[j]+"</option>";
        }
        y += "</select>";
        return y;
    }
    
    public static String addCheckBoxInput(String name, String val, String[] opts)
    {
        String y = "";
        return y;
    }
    
    public static String addRadioInput(String name, String val, String[] opts) 
    {
        String y = "";
        return y;
    }
    
    public static String asHTMLForm(String         action,
                                    int            maxCols, // how do I use it?
                                    List<String>   keys, 
                                    List<String>   names, 
                                    List<String>   values,
                                    List<String>   types,
                                    List<String[]> opts)
    {
        String y = "<div><form method=post action=ActionDispatch name=action_"+action+" onsubmit=\"disableSubmit()\"><table><tr>";
        /* m m m 
        for (int i = 0; i < keys.size(); i++) {
            String tit = keys.get(i);
            String ty  = types.get(i);
            if (ty == null) {
                continue;
            }
            y += "<td><p>"+tit+"</p></td>";
        }*/
        y += "</tr>";
        for (int i = 0; i < keys.size(); i++) {
            String   name = names.get(i);
            String   val  = values.get(i);
            String[] opt  = opts.get(i);
            String   ty   = types.get(i);
            String   tit  = keys.get(i);
            if (ty == null) {
                continue;
            }
            y += "<tr><td><p>"+tit+"</p></td>";
            y += "<td XXXstyle='border-right:solid 1px gray'><p>";
            if (ty == "plain") { 
                y += addPlainText(name, val, opt);
            }
            else if (ty == "text") { 
                y += addTextInput(name, val, true);
            }
            else if (ty == "textdis") { 
                y += addTextInput(name, val, false);
            }
            else if (ty == "checkbox") {
                y += addCheckBoxInput(name, val, opt);
            }
            else if (ty == "radio") {
                y += addRadioInput(name, val, opt);        
            }
            else if (ty == "select") {
                y += addSelectInput(name, val, opt);
            }
            else if (ty == "submit") {
                y += addSubmitInput(name, val, opt);
            }
            else if (ty == "hidden") {
                y += addHiddenInput(name, val, opt);
            }
            else if (ty == "button") {
                y += addButton(name, val, opt);
            }
            y += "</p></td>";
            y += "</tr>";
        }        
                
        y += "<td><input type=hidden value="+action+" name=action ></input></td>";
        
        y += "</tr></table></form></div>";
        return y;
    }
    
    public static String toCamelCase(String x, boolean preserve) {
        if (x.length() < 1) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        sb.append(Character.toUpperCase(x.charAt(0)));
        if (x.length() > 1) {
            String w = x.substring(1, x.length());
            if (!preserve) {
                w = w.toLowerCase();
            }
            sb.append(w);
        }
        String y  = new String(sb);
        return y;
    }
    
    public static String[] splitStringToArray(String s, boolean useCaps) {
        if (s == null) {
            return null;
        }
        String[] ss = s.split("[;]+");
        if (ss.length < 1) {
            return null;
        }
        if (!useCaps) {
            String x = ss[0];
            ss[0] = toCamelCase(ss[0], true); // Preserve rest of string
            return ss;
        }
        for (int i = 0; i < ss.length; i++) {
            String t = ss[i];
            String y = "";
            for (String x : t.split(" ")) {
                y += toCamelCase(x, false); // modify rest of string
            }
            ss[i] = y;
        }
        return ss;
    }
                
    public static void handleException(Exception e) 
    {
        // Mostly for debugging
        e.printStackTrace();
        return;
    }

}

